//**********************************************************************
//	Programmer	-	Sujal Bista
//	File Name	-	modelQuick.cpp
//	Description	:	
//					quick 3d model handler
//
//**********************************************************************
#include "modelQuick.h"
#include "model.h"
using namespace std;

#ifdef _MSC_VER
	#ifdef _DEBUG
		#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__)
		#define new DEBUG_NEW
	#else
		#define DEBUG_NEW new
	#endif
#endif


//convert model to modelquick
modelQuick& modelQuick::operator=(const model& data)
{
	clear();

	unsigned int staticMeshDataSize=sizeof(meshHeader);
	unsigned int memoryIndex=0;

	//find in bytes total size required my mesh data
	for(unsigned int i=0;i<data.staticMeshHeader.meshCount;i++)
	{
		staticMeshDataSize+=sizeof(meshData);
		staticMeshDataSize+=data.staticMeshHeader.meshes[i].vertexCount*sizeof(meshData::vertexData);
		staticMeshDataSize+=data.staticMeshHeader.meshes[i].faceCount*sizeof(meshData::faceData);
		staticMeshDataSize+=data.staticMeshHeader.meshes[i].materialCount*sizeof(meshData::materialData);
	}

	//find in bytes total size required my animation data
	for(unsigned int i=0;i<data.staticMeshHeader.animationCount;i++)
	{
		staticMeshDataSize+=sizeof(animationData);
		for(unsigned int j=0;j<data.staticMeshHeader.animations[i].boneAnimationCount;j++)
		{
			staticMeshDataSize+=sizeof(animationData::boneAnimationData);
			staticMeshDataSize+=data.staticMeshHeader.animations[i].boneAnimations[j].rotationCount*sizeof(animationData::boneAnimationData::floatQuaternionKey);
			staticMeshDataSize+=data.staticMeshHeader.animations[i].boneAnimations[j].scaleCount*sizeof(animationData::boneAnimationData::float3SKey);
			staticMeshDataSize+=data.staticMeshHeader.animations[i].boneAnimations[j].translationCount*sizeof(animationData::boneAnimationData::float3SKey);
			
		}
	}

	//find in bytes total size required my skin data
	for(unsigned int i=0;i<data.staticMeshHeader.skinCount;i++)
	{
		staticMeshDataSize+=sizeof(skinData);
		for(unsigned int j=0;j<data.staticMeshHeader.skins[i].boneCount;j++)
		{
			staticMeshDataSize+=sizeof(skinData::boneData);
			staticMeshDataSize+=data.staticMeshHeader.skins[i].bones[j].influenceCount*sizeof(unsigned int);
			staticMeshDataSize+=data.staticMeshHeader.skins[i].bones[j].influenceCount*sizeof(float);

		}
		staticMeshDataSize+=data.staticMeshHeader.skins[i].boneHierarchyCount*sizeof(skinData::boneHierarchyData);
	}
	
	//allocate the data
	staticMeshDataLength=staticMeshDataSize;
	staticMeshData=new unsigned char[staticMeshDataLength];
	staticMeshHeader=(meshHeader *)staticMeshData;
	memoryIndex+=sizeof(meshHeader);

	//now save the data
	staticMeshHeader->meshCount=data.staticMeshHeader.meshCount;
	staticMeshHeader->animationCount=data.staticMeshHeader.animationCount;
	staticMeshHeader->skinCount=data.staticMeshHeader.skinCount;

	//all the meshes
	staticMeshHeader->_forceSpace64_0=memoryIndex+(UINT64) staticMeshData;
	memoryIndex+=sizeof(meshData)*staticMeshHeader->meshCount;
	//animations
	staticMeshHeader->_forceSpace64_1=memoryIndex+(UINT64) staticMeshData;
	memoryIndex+=sizeof(animationData)*staticMeshHeader->animationCount;
	//skins
	staticMeshHeader->_forceSpace64_2=memoryIndex+(UINT64) staticMeshData;
	memoryIndex+=sizeof(skinData)*staticMeshHeader->skinCount;

	//copy mesh
	for(unsigned int i=0;i<data.staticMeshHeader.meshCount;i++)
	{
		strncpy(staticMeshHeader->meshes[i].name,data.staticMeshHeader.meshes[i].name,MAX_NAME-1);
		staticMeshHeader->meshes[i].vertexCount=data.staticMeshHeader.meshes[i].vertexCount;
		staticMeshHeader->meshes[i].faceCount=data.staticMeshHeader.meshes[i].faceCount;
		staticMeshHeader->meshes[i].materialCount=data.staticMeshHeader.meshes[i].materialCount;

		staticMeshHeader->meshes[i]._forceSpace64_0=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(meshData::vertexData)*staticMeshHeader->meshes[i].vertexCount;

		staticMeshHeader->meshes[i]._forceSpace64_1=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(meshData::faceData)*staticMeshHeader->meshes[i].faceCount;

		staticMeshHeader->meshes[i]._forceSpace64_2=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(meshData::materialData)*staticMeshHeader->meshes[i].materialCount;

		for(unsigned int j=0;j<data.staticMeshHeader.meshes[i].vertexCount;j++)
			staticMeshHeader->meshes[i].vertices[j]=data.staticMeshHeader.meshes[i].vertices[j];

		for(unsigned int j=0;j<data.staticMeshHeader.meshes[i].faceCount;j++)
			staticMeshHeader->meshes[i].faces[j]=data.staticMeshHeader.meshes[i].faces[j];

		for(unsigned int j=0;j<data.staticMeshHeader.meshes[i].materialCount;j++)
			staticMeshHeader->meshes[i].materials[j]=data.staticMeshHeader.meshes[i].materials[j];
	}

	//copy animation
	for(unsigned int i=0;i<data.staticMeshHeader.animationCount;i++)
	{
		strncpy(staticMeshHeader->animations[i].name,data.staticMeshHeader.animations[i].name,MAX_NAME-1);
		staticMeshHeader->animations[i].boneAnimationCount=data.staticMeshHeader.animations[i].boneAnimationCount;
		staticMeshHeader->animations[i].ticksPerSecond=data.staticMeshHeader.animations[i].ticksPerSecond;
		
		staticMeshHeader->animations[i]._forceSpace64_0=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(animationData::boneAnimationData)*staticMeshHeader->animations[i].boneAnimationCount;
		
		for(unsigned int j=0;j<data.staticMeshHeader.animations[i].boneAnimationCount;j++)
		{
			strncpy(staticMeshHeader->animations[i].boneAnimations[j].name,data.staticMeshHeader.animations[i].boneAnimations[j].name,MAX_NAME-1);
			staticMeshHeader->animations[i].boneAnimations[j].rotationCount=data.staticMeshHeader.animations[i].boneAnimations[j].rotationCount;
			staticMeshHeader->animations[i].boneAnimations[j].scaleCount=data.staticMeshHeader.animations[i].boneAnimations[j].scaleCount;
			staticMeshHeader->animations[i].boneAnimations[j].translationCount=data.staticMeshHeader.animations[i].boneAnimations[j].translationCount;
			
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_0=memoryIndex+(UINT64)staticMeshData;
			memoryIndex+=sizeof(animationData::boneAnimationData::floatQuaternionKey)*staticMeshHeader->animations[i].boneAnimations[j].rotationCount;

			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_1=memoryIndex+(UINT64)staticMeshData;
			memoryIndex+=sizeof(animationData::boneAnimationData::float3SKey)*staticMeshHeader->animations[i].boneAnimations[j].scaleCount;

			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_2=memoryIndex+(UINT64)staticMeshData;
			memoryIndex+=sizeof(animationData::boneAnimationData::float3SKey)*staticMeshHeader->animations[i].boneAnimations[j].translationCount;

			for(unsigned int k=0;k<staticMeshHeader->animations[i].boneAnimations[j].rotationCount;k++)
				staticMeshHeader->animations[i].boneAnimations[j].rotations[k]=data.staticMeshHeader.animations[i].boneAnimations[j].rotations[k];

			for(unsigned int k=0;k<staticMeshHeader->animations[i].boneAnimations[j].scaleCount;k++)
				staticMeshHeader->animations[i].boneAnimations[j].scales[k]=data.staticMeshHeader.animations[i].boneAnimations[j].scales[k];

			for(unsigned int k=0;k<staticMeshHeader->animations[i].boneAnimations[j].translationCount;k++)
				staticMeshHeader->animations[i].boneAnimations[j].translations[k]=data.staticMeshHeader.animations[i].boneAnimations[j].translations[k];
		}		
	}

	//copy skin
	for(unsigned int i=0;i<data.staticMeshHeader.skinCount;i++)
	{
		staticMeshHeader->skins[i].boneCount=data.staticMeshHeader.skins[i].boneCount;
		staticMeshHeader->skins[i].boneHierarchyCount=data.staticMeshHeader.skins[i].boneHierarchyCount;

		staticMeshHeader->skins[i]._forceSpace64_0=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(skinData::boneData)*staticMeshHeader->skins[i].boneCount;

		staticMeshHeader->skins[i]._forceSpace64_1=memoryIndex+(UINT64)staticMeshData;
		memoryIndex+=sizeof(skinData::boneHierarchyData)*staticMeshHeader->skins[i].boneHierarchyCount;

		//this must be changed
		staticMeshHeader->skins[i].rootIndex=data.staticMeshHeader.skins[i].rootIndex;

		for(unsigned int j=0;j<staticMeshHeader->skins[i].boneCount;j++)
		{
			strncpy(staticMeshHeader->skins[i].bones[j].name,data.staticMeshHeader.skins[i].bones[j].name,MAX_NAME-1);
			staticMeshHeader->skins[i].bones[j].offsetMatrix=data.staticMeshHeader.skins[i].bones[j].offsetMatrix;
			staticMeshHeader->skins[i].bones[j].boneHierarchyIndex=data.staticMeshHeader.skins[i].bones[j].boneHierarchyIndex;
			staticMeshHeader->skins[i].bones[j].influenceCount=data.staticMeshHeader.skins[i].bones[j].influenceCount;

			staticMeshHeader->skins[i].bones[j]._forceSpace64_0=memoryIndex+(UINT64)staticMeshData;
			memoryIndex+=sizeof(unsigned int)*staticMeshHeader->skins[i].bones[j].influenceCount;

			staticMeshHeader->skins[i].bones[j]._forceSpace64_1=memoryIndex+(UINT64)staticMeshData;
			memoryIndex+=sizeof(float)*staticMeshHeader->skins[i].bones[j].influenceCount;

			for(unsigned int k=0;k<staticMeshHeader->skins[i].bones[j].influenceCount;k++)
			{
				staticMeshHeader->skins[i].bones[j].vertexIndex[k]=data.staticMeshHeader.skins[i].bones[j].vertexIndex[k];
				staticMeshHeader->skins[i].bones[j].weights[k]=data.staticMeshHeader.skins[i].bones[j].weights[k];
			}
		}

		for(unsigned int j=0;j<staticMeshHeader->skins[i].boneHierarchyCount;j++)
			staticMeshHeader->skins[i].bonesHierarchy[j]=data.staticMeshHeader.skins[i].bonesHierarchy[j];

	}


	//create one instace
	float4x4 temp;
	temp.identity();

	//add instances
	instances.addBack(instanceData(&staticMeshHeader->meshes[0],&staticMeshHeader->skins[0],&staticMeshHeader->animations[0],temp));
	
	//initialize all the instances
	for(unsigned int i=0;i<instances.size();i++)
		instances[i].initialize();


	return *this;
}

//init
bool modelQuick::init(graphicsUtility &glu)
{
	graphicsDefinitions::TEXTURE_ADDRESS_MODE addMode[3]=
		{
			graphicsDefinitions::TEXTURE_ADDRESS_MODE_CLAMP,
			graphicsDefinitions::TEXTURE_ADDRESS_MODE_CLAMP,
			graphicsDefinitions::TEXTURE_ADDRESS_MODE_CLAMP
		};
	float borderColor[4]={0,0,0,0};
	//get device
	device &graphicsDevice=glu.getDevice();

	for(unsigned int i=0;i<staticMeshHeader->meshCount;i++)
	{
		meshData &currMesh=staticMeshHeader->meshes[i];
		for(unsigned int j=0;j<currMesh.materialCount;j++)
		{
			meshData::materialData &currMaterial=currMesh.materials[j];
			
			if(currMaterial.textureSRV || currMaterial.textureSampler)
				continue;

			currMaterial.textureSRV= new shaderResourceView;
			currMaterial.textureSampler= new samplerState;

			//create the texture
			if(!graphicsDevice.createShaderResourceViewFromFile(currMaterial.fileName,(currMaterial.textureSRV)))
				return false;
					
			//create the sampler
			if(!graphicsDevice.createSamplerState(
					graphicsDefinitions::FILTER_MIN_MAG_MIP_LINEAR,
					addMode,
					0,
					0,
					graphicsDefinitions::COMPARISON_FUNC_NEVER,
					borderColor,
					0,
					10000,
					currMaterial.textureSampler
				))
				return false;
		}
	}

	return true;
}

//updates the mesh
void modelQuick::update(const float &dt)
{
	//update all the instances
	for(unsigned int i=0;i<instances.size();i++)
	{		
		instanceData &currInstance=instances[i];

		//update the instance
		currInstance.update(dt);
	}
}

//show the mesh
void modelQuick::show(graphicsUtility &glu,const camera &eye,const bool useTexture)
{
	//update all the instances
	for(unsigned int i=0;i<instances.size();i++)
	{		
		instanceData &currInstance=instances[i];

		//shows an instance
		currInstance.show(glu,eye,useTexture);
	}
}

//reads compact content in the file
bool modelQuick::read(char *fileName)
{
	//clear the current memory
	clear();

		//reads entire file
	if(!readFile(fileName, staticMeshData, staticMeshDataLength))
		return false;
	staticMeshHeader=(meshHeader *)staticMeshData;

	//converters offset to memory address
	convertOffsetToMemoryAddress();

		//create one instace
	float4x4 temp;
	temp.identity();

	//add instances
	instances.addBack(instanceData(&staticMeshHeader->meshes[0],&staticMeshHeader->skins[0],&staticMeshHeader->animations[0],temp));
	
	//initialize all the instances
	for(unsigned int i=0;i<instances.size();i++)
		instances[i].initialize();

	return true;
}

//writes compact content in the file
bool modelQuick::write(char *fileName)
{
	//converters memory address to offset
	convertMemoryAddressToOffset();
		
	//writes entire file
	writeFile(fileName, staticMeshData,staticMeshDataLength);

	//converters offset to memory address
	convertOffsetToMemoryAddress();

	return true;
}

//converters memory address to offset
void modelQuick::convertMemoryAddressToOffset(void)
{
	//copy mesh
	for(unsigned int i=0;i<staticMeshHeader->meshCount;i++)
	{
		staticMeshHeader->meshes[i]._forceSpace64_0=staticMeshHeader->meshes[i]._forceSpace64_0-(UINT64)staticMeshData;
		staticMeshHeader->meshes[i]._forceSpace64_1=staticMeshHeader->meshes[i]._forceSpace64_1-(UINT64)staticMeshData;
		staticMeshHeader->meshes[i]._forceSpace64_2=staticMeshHeader->meshes[i]._forceSpace64_2-(UINT64)staticMeshData;
	}

	//copy animation
	for(unsigned int i=0;i<staticMeshHeader->animationCount;i++)
	{
		for(unsigned int j=0;j<staticMeshHeader->animations[i].boneAnimationCount;j++)
		{
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_0=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_0-(UINT64)staticMeshData;
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_1=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_1-(UINT64)staticMeshData;
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_2=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_2-(UINT64)staticMeshData;
		}	
		staticMeshHeader->animations[i]._forceSpace64_0=staticMeshHeader->animations[i]._forceSpace64_0-(UINT64)staticMeshData;
	}

	//copy skin
	for(unsigned int i=0;i<staticMeshHeader->skinCount;i++)
	{
		for(unsigned int j=0;j<staticMeshHeader->skins[i].boneCount;j++)
		{
			staticMeshHeader->skins[i].bones[j]._forceSpace64_0=staticMeshHeader->skins[i].bones[j]._forceSpace64_0-(UINT64)staticMeshData;
			staticMeshHeader->skins[i].bones[j]._forceSpace64_1=staticMeshHeader->skins[i].bones[j]._forceSpace64_1-(UINT64)staticMeshData;
		}
		staticMeshHeader->skins[i]._forceSpace64_0=staticMeshHeader->skins[i]._forceSpace64_0-(UINT64)staticMeshData;
		staticMeshHeader->skins[i]._forceSpace64_1=staticMeshHeader->skins[i]._forceSpace64_1-(UINT64)staticMeshData;
	}
	
	//all the meshes
	staticMeshHeader->_forceSpace64_0=staticMeshHeader->_forceSpace64_0-(UINT64)staticMeshData;
	//animations
	staticMeshHeader->_forceSpace64_1=staticMeshHeader->_forceSpace64_1-(UINT64)staticMeshData;
	//skins
	staticMeshHeader->_forceSpace64_2=staticMeshHeader->_forceSpace64_2-(UINT64)staticMeshData;

}

//converters offset to memory address
void modelQuick::convertOffsetToMemoryAddress(void)
{
	//all the meshes
	staticMeshHeader->_forceSpace64_0=staticMeshHeader->_forceSpace64_0+(UINT64)staticMeshData;
	//animations
	staticMeshHeader->_forceSpace64_1=staticMeshHeader->_forceSpace64_1+(UINT64)staticMeshData;
	//skins
	staticMeshHeader->_forceSpace64_2=staticMeshHeader->_forceSpace64_2+(UINT64)staticMeshData;

	//copy mesh
	for(unsigned int i=0;i<staticMeshHeader->meshCount;i++)
	{
		staticMeshHeader->meshes[i]._forceSpace64_0=staticMeshHeader->meshes[i]._forceSpace64_0+(UINT64)staticMeshData;
		staticMeshHeader->meshes[i]._forceSpace64_1=staticMeshHeader->meshes[i]._forceSpace64_1+(UINT64)staticMeshData;
		staticMeshHeader->meshes[i]._forceSpace64_2=staticMeshHeader->meshes[i]._forceSpace64_2+(UINT64)staticMeshData;
	}

	//copy animation
	for(unsigned int i=0;i<staticMeshHeader->animationCount;i++)
	{
		staticMeshHeader->animations[i]._forceSpace64_0=staticMeshHeader->animations[i]._forceSpace64_0+(UINT64)staticMeshData;
		for(unsigned int j=0;j<staticMeshHeader->animations[i].boneAnimationCount;j++)
		{
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_0=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_0+(UINT64)staticMeshData;
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_1=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_1+(UINT64)staticMeshData;
			staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_2=staticMeshHeader->animations[i].boneAnimations[j]._forceSpace64_2+(UINT64)staticMeshData;
		}		
	}

	//copy skin
	for(unsigned int i=0;i<staticMeshHeader->skinCount;i++)
	{
		staticMeshHeader->skins[i]._forceSpace64_0=staticMeshHeader->skins[i]._forceSpace64_0+(UINT64)staticMeshData;
		staticMeshHeader->skins[i]._forceSpace64_1=staticMeshHeader->skins[i]._forceSpace64_1+(UINT64)staticMeshData;
		for(unsigned int j=0;j<staticMeshHeader->skins[i].boneCount;j++)
		{
			staticMeshHeader->skins[i].bones[j]._forceSpace64_0=staticMeshHeader->skins[i].bones[j]._forceSpace64_0+(UINT64)staticMeshData;
			staticMeshHeader->skins[i].bones[j]._forceSpace64_1=staticMeshHeader->skins[i].bones[j]._forceSpace64_1+(UINT64)staticMeshData;
		}
	}
}